import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_getx/app/base/load_image.dart';
import 'package:flutter_getx/app/base/my_button.dart';
import 'package:flutter_getx/core/utils/device_utils.dart';
import 'package:flutter_getx/ext/ext.dart';
import 'package:flutter_getx/res/colors/colors.dart';
import 'package:flutter_getx/res/dimens/dimens.dart';
import 'package:flutter_getx/res/gaps.dart';
import 'package:flutter_getx/res/strings/strings.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

/// 登录模块的输入框封装
class MyTextField extends StatefulWidget {
  const MyTextField(
      {Key? key,
      required this.controller,
      this.maxLength = 16,
      this.autofocus = false,
      this.keyboardType = TextInputType.text,
      this.hintText = '',
      this.focusNode,
      this.isInputPwd = false,
      this.prefixText = '',
      this.getVCode,
      this.lableText = '',
      this.contentPadding,
      this.isCollapsed = false,
      this.textAlign = TextAlign.start,
      this.decoration,
      this.inputFormatters,
      this.textInputAction,
        this.onSaved,
        this.validator,
        this.autovalidateMode,
      this.keyName})
      : super(key: key);

  final TextEditingController controller;
  final int maxLength;
  final bool autofocus;
  final TextInputType keyboardType;
  final String hintText;
  final FocusNode? focusNode;
  final bool isInputPwd;
  final Future<bool> Function()? getVCode;
  final String prefixText;
  final String lableText;
  final EdgeInsetsGeometry? contentPadding;
  final bool isCollapsed;
  final TextAlign textAlign;
  final InputDecoration? decoration;
  final List<TextInputFormatter>? inputFormatters;
  final TextInputAction? textInputAction;
  final FormFieldSetter<String>? onSaved;
  final FormFieldValidator<String>? validator;
  final AutovalidateMode? autovalidateMode;

  /// 用于集成测试寻找widget
  final String? keyName;

  @override
  _MyTextFieldState createState() => _MyTextFieldState();
}

class _MyTextFieldState extends State<MyTextField> {
  bool _isShowPwd = false;
  bool _isShowDelete = false;
  bool _clickable = true;

  /// 倒计时秒数
  final int _second = 60;

  /// 当前秒数
  late int _currentSecond;
  StreamSubscription? _subscription;

  @override
  void initState() {
    /// 获取初始化值
    _isShowDelete = widget.controller.text.isNotEmpty;

    /// 监听输入改变
    widget.controller.addListener(isEmpty);
    super.initState();
  }

  void isEmpty() {
    final bool isNotEmpty = widget.controller.text.isNotEmpty;

    /// 状态不一样在刷新，避免重复不必要的setState
    if (isNotEmpty != _isShowDelete) {
      setState(() {
        _isShowDelete = isNotEmpty;
      });
    }
  }

  @override
  void dispose() {
    _subscription?.cancel();
    widget.controller.removeListener(isEmpty);
    super.dispose();
  }

  Future _getVCode() async {
    final bool isSuccess = await widget.getVCode!();
    if (isSuccess != null && isSuccess) {
      setState(() {
        _currentSecond = _second;
        _clickable = false;
      });
      _subscription = Stream.periodic(const Duration(seconds: 1), (int i) => i)
          .take(_second)
          .listen((int i) {
        setState(() {
          _currentSecond = _second - i - 1;
          _clickable = _currentSecond < 1;
        });
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    final ThemeData themeData = Theme.of(context);

    Widget textField = TextFormField(
      onSaved: widget.onSaved,
      validator: widget.validator,
      autovalidateMode: widget.autovalidateMode,
      textAlign: widget.textAlign,
      focusNode: widget.focusNode,
      maxLength: widget.maxLength,
      obscureText: widget.isInputPwd && !_isShowPwd,
      autofocus: widget.autofocus,
      controller: widget.controller,
      textInputAction: widget.textInputAction ?? TextInputAction.done,
      keyboardType: widget.keyboardType,
      style: TextStyle(fontSize: Sp.sp16, color: colorText),
      // 数字、手机号限制格式为0到9， 密码限制不包含汉字
      inputFormatters: widget.inputFormatters ??
          ((widget.keyboardType == TextInputType.number ||
                  widget.keyboardType == TextInputType.phone)
              ? [FilteringTextInputFormatter.allow(RegExp('[0-9]'))]
              : [FilteringTextInputFormatter.deny(RegExp('[\u4e00-\u9fa5]'))]),
      decoration: widget.decoration ??
          InputDecoration(
            isCollapsed: widget.isCollapsed,
            prefixText: widget.prefixText,
            prefixStyle: TextStyle(fontSize: Sp.sp14, color: colorText),
            contentPadding: widget.contentPadding,
            labelText: widget.lableText.isEmpty ? null : widget.lableText,
            hintText: widget.hintText.isEmpty ? null : widget.hintText,
            hintStyle: TextStyle(fontSize: Sp.sp13, color: colorTextHint),
            alignLabelWithHint: true,
            labelStyle: TextStyle(fontSize: Sp.sp14, color: colorTextHint),
            counterText: '',
            focusedBorder: UnderlineInputBorder(
              borderSide: BorderSide(
                color: themeData.primaryColor,
                width: 0.8,
              ),
            ),
            enabledBorder: UnderlineInputBorder(
              borderSide: BorderSide(
                color: Theme.of(context).dividerTheme.color!,
                width: 0.8,
              ),
            ),
          ),
    );

    /// 个别Android机型（华为、vivo）的密码安全键盘不弹出问题（已知小米正常），临时修复方法：https://github.com/flutter/flutter/issues/68571 (issues/61446)
    /// 怀疑是安全键盘与三方输入法之间的切换冲突问题。
    if (Device.isAndroid) {
      textField = Listener(
        onPointerDown: (e) =>
            FocusScope.of(context).requestFocus(widget.focusNode),
        child: textField,
      );
    }

    Widget? clearButton;

    if (_isShowDelete) {
      clearButton = Semantics(
        label: 'Clear',
        hint: 'Clear input',
        child: GestureDetector(
          child: LoadAssetImage(
            'ic_tf_delete'.pathLogin,
            key: Key('${widget.keyName}_delete'),
            width: ScreenUtil().setWidth(14.0),
            height: ScreenUtil().setWidth(32.0),
          ),
          onTap: () => widget.controller.text = '',
        ),
      );
    }

    late Widget pwdVisible;
    if (widget.isInputPwd) {
      pwdVisible = Semantics(
        label: 'Password visible switch',
        hint: 'The password is visible',
        child: GestureDetector(
          child: LoadAssetImage(
            _isShowPwd ? 'ic_tf_display'.pathLogin : 'ic_tf_hide'.pathLogin,
            key: Key('${widget.keyName}_showPwd'),
            width: ScreenUtil().setWidth(14.0),
            height: ScreenUtil().setWidth(32.0),
          ),
          onTap: () {
            setState(() {
              _isShowPwd = !_isShowPwd;
            });
          },
        ),
      );
    }

    late Widget getVCodeButton;
    if (widget.getVCode != null) {
      getVCodeButton = MyButton(
        key: const Key('getVerificationCode'),
        onPressed: _clickable ? _getVCode : null,
        fontSize: Sp.sp14,
        text: _clickable ? OTP : '（$_currentSecond s）',
        textColor: themeData.primaryColor,
        disabledTextColor: colorTextDisabled,
        backgroundColor: Colors.transparent,
        disabledBackgroundColor: colorBgDisabled,
        radius: 1.0,
        minHeight: 26.0,
        minWidth: 76.0,
        padding: const EdgeInsets.symmetric(horizontal: 8.0),
        side: BorderSide(
          color: _clickable ? themeData.primaryColor : Colors.transparent,
          width: 0.8,
        ),
      );
    }

    return Stack(
      alignment: Alignment.centerRight,
      children: <Widget>[
        textField,
        Row(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            /// _isShowDelete参数动态变化，为了不破坏树结构使用Visibility，false时放一个空Widget。
            /// 对于其他参数，为初始配置参数，基本可以确定树结构，就不做空Widget处理。
            Visibility(
              visible: _isShowDelete,
              child: clearButton ?? Gaps.empty,
            ),
            if (widget.isInputPwd) SizedBox(width: Dp.dp_15,),
            if (widget.isInputPwd) pwdVisible,
            if (widget.getVCode != null) SizedBox(width: Dp.dp_15,),
            if (widget.getVCode != null) getVCodeButton,
            if (widget.contentPadding != null)
              SizedBox(
                width: Dp.dp_10,
              ),
          ],
        )
      ],
    );
  }
}
